# Higher level wrappers for the SQLPSX-derived functions

function script:GetBackupFile([string]$dir=$Path, [string]$ext="bak")
{
    $dir | ConvertTo-FullPath | Join-Path -Child "$DatabaseName.$ext"
}

function Backup-SqlDatabase 
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, Position=0)]
        [Microsoft.SqlServer.Management.Smo.Server]$Server,
        [parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
        [string]$DatabaseName,
        [parameter(Mandatory=$true, Position=2)]
        [string]$Path      
    )
        
    process 
    {            
        write-verbose "Backing up $DatabaseName to $Path from $($Server.Name)"
      
        # local paths get interpreted relative to the database server
        mkdir $Path -Force | 
            ConvertTo-Path | 
            Test-Path2 -Unc -Throw
        
        Invoke-SqlBackup $Server $DatabaseName (GetBackupFile) -Force -CopyOnly
    }
}

function Convert-RedGateBackup
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, ValueFromPipeline=$true)]
        [string]$DatabaseName,
        [parameter(Mandatory=$true, Position=0)]
        [string]$Path,
        [parameter(Mandatory=$true, Position=1)]
        [string]$Destination,
        [parameter(Mandatory=$true, Position=2)]
        [string]$SqbConverter
    )
    
    process
    {
        write-verbose "Unpacking $DatabaseName from RedGate backup at $Path to $Destination using $SqbConverter"
    
        $Path, $Destination | Test-Path2 -Throw -Folder
        $SqbConverter | Test-Path2 -Throw       
        
        dir $Destination -Filter "$DatabaseName*" | 
            del -Force
                
        & $SqbConverter (GetBackupFile -ext "sqb") (GetBackupFile -dir $Destination)
    }
}

function Restore-SqlDatabase
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, Position=0)]
        [Microsoft.SqlServer.Management.Smo.Server]$Server,
        [parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
        [string]$DatabaseName,
        [parameter(Mandatory=$true, Position=2)]
        [string]$Path,                
        [parameter()]
        [string]$DataDir        
    )
    
    filter PathCoalesce($alt) { $_ | ?? $alt {Test-Path2 $_} }
        
    process 
    {
        write-verbose "Restoring $DatabaseName from $Path to $($Server.Name) using $DataDir"
    
        # find physical path for data files in restored db                        
        try { $existingDB = Get-SqlDatabase $Server $DatabaseName }            
        catch { }
        $masterDB = Get-SqlDatabase $Server master -Force
        $DataDir = $DataDir |
            PathCoalesce $existingDB.PrimaryFilePath |
            PathCoalesce $masterDB.PrimaryFilePath
        Test-Path2 $DataDir -Folder -Throw
        
        # find source file
        Test-Path2 $Path -Folder -Throw 
        $backupFile = (GetBackupFile)
        if (!(Test-Path2 $backupFile))
        {            
            # assume there's a converted Red Gate backup
            $backupFile = dir $Path -Filter "$DatabaseName*.bak" |
                select -Expand FullName
            if(-not $backupFile) { 
                throw "Could not find source file(s) for backup" 
            }
        }
        
        $Server.KillAllProcesses($_) 
        Invoke-SqlRestore $Server $DatabaseName $backupFile -Force -DataDir $DataDir
    }
}

function Compress-Database
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$True, Position=0)]
        [Microsoft.SqlServer.Management.Smo.Database]$Database
    )
    process
    {
        write-verbose "Compressing $Database"
        
        # rebuild all indexes
        $Database | %{ $_.tables } | %{ $_.indexes } |
            % { $_.Rebuild() }
            
        # truncate transaction log
        $Database.TruncateLog();
        # move all pages to the front of data files (leaving 5% free space) and release the rest to the OS
        $Database.Shrink(5, [Microsoft.SqlServer.Management.Smo.ShrinkMethod]::Default);
    }
}